package com.ruoyi.project.storage.service.impl;

import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.project.common.enums.OrderOpreate;
import com.ruoyi.project.common.enums.RecordPointWay;
import com.ruoyi.project.common.util.ParameterUtil;
import com.ruoyi.project.common.util.SeqGeneratorUtil;
import com.ruoyi.project.storage.domain.BoxInfo;
import com.ruoyi.project.storage.domain.User;
import com.ruoyi.project.storage.domain.vo.OrderVO;
import com.ruoyi.project.storage.mapper.BoxInfoMapper;
import com.ruoyi.project.storage.mapper.OrderMapper;
import com.ruoyi.project.storage.mapper.UserMapper;
import com.ruoyi.project.storage.service.IOrderService;
import com.ruoyi.project.storage.service.IPointService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.List;

import static com.ruoyi.framework.datasource.DynamicDataSourceContextHolder.log;

/**
 * 请添加注释
 *
 * @author mengyuanqing
 * @date 2020/5/13
 */
@Service
public class OrderServiceImpl implements IOrderService {
    // 定义开关项
    private static final String OPEN = "a";
    // 定义wifi模块ip
    private static final String HOST = "192.168.1.212";
    // 定义wifi模块端口
    private static final int PORT = 8080;
    // 通过注释注入
    @Autowired
    private IPointService pointService;
    // 通过注释注入
    @Autowired
    private BoxInfoMapper boxInfoMapper;
    // 通过注释注入
    @Autowired
    private UserMapper userMapper;
    // 通过注释注入
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 查询订单列表
     *
     * @param orderVO 订单对象
     * @return 列表
     */
    @Override
    public List<OrderVO> selectOrderList(OrderVO orderVO) {
        // 返回查询结果
        return orderMapper.selectOrderList(orderVO);
    }

    /**
     * 预约
     *
     * @param orderVO 对象
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertOrderList(OrderVO orderVO) {
        // 校验预约时长是否大于等于1一个小时
        if (orderVO.getLeaseDuration() >= 1) {
            // 获取当前用户积分
            Long points = userMapper.selectCurrentPoints(SecurityUtils.getUserId());
            // 判断总共积分是否大于当前用户积分
            if (points >= orderVO.getTotalPrice()) {
                // 实例化一个箱子信息对象
                BoxInfo boxInfo = new BoxInfo();
                // 从预约订单中获取箱子规格
                boxInfo.setBoxStandard(orderVO.getBoxStandard());
                // 从预约订单中获取每月积分价格
                boxInfo.setBoxUnitPrice(orderVO.getBoxUnitPrice());
                // 拿到了箱子的值
                boxInfo = distributeBox(boxInfo);
                // 如果没取到箱子信息
                if (boxInfo == null) {
                    log.error("OrderServiceImpl.insertOrderList failed: 乐观锁");
                    throw new CustomException("暂无空箱");
                }
                // 实例化一个用户对象
                User user = new User();
                // 设置到用户当前积分中
                user.setCurrentPoints(-orderVO.getTotalPrice());
                // 设置基础字段
                ParameterUtil.setUpdateEntity(user);
                // 设置userId
                user.setUserId(SecurityUtils.getUserId());
                // 插入用户使用完箱子后的积分
                userMapper.operateUserPoints(user);
                // 设置订单编号
                orderVO.setOrderCode(Long.valueOf(SeqGeneratorUtil.seqGenerator(DateUtils.getNowDateStr(), 6)));
                // 设置插入Oder表的基础字段
                ParameterUtil.setCreateEntity(orderVO);
                // 设置箱子编号
                orderVO.setBoxCode(boxInfo.getBoxCode());
                // 设置箱子id
                orderVO.setBoxId(boxInfo.getId());
                // 设置状态
                orderVO.setStatus(1);
                // 设置未删除
                orderVO.setDelFlag("0");
                // 设置app端未删除
                orderVO.setAppDelFlag(0);
                // 设置后台端未删除
                orderVO.setBackendDelFlag(0);
                // 设置昵称
                orderVO.setNickName(user.getNickName());
                // 设置用户id
                orderVO.setUserId(SecurityUtils.getUserId());
                // 生成订单
                orderMapper.insertOrderList(orderVO);
                // 开启柜门
                openKey();
            } else {
                //
                throw new CustomException("当前用户积分不足");
            }
        } else {
            throw new CustomException("预约时间太短");
        }
        // 插入积分记录成功
        return pointService.insertPointRecord(RecordPointWay.ORDER, orderVO.getUserId(), -orderVO.getTotalPrice(), null, orderVO.getId());
    }

    /**
     * 分配箱子
     *
     * @param boxInfo 箱子信息对象
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public BoxInfo distributeBox(BoxInfo boxInfo) {
        // 获取当前规格下可用的箱子
        List<BoxInfo> list = boxInfoMapper.selectNowBoxStandardBoxId(boxInfo);
        // 判断list不为空
        if (!list.isEmpty()) {
            // 取到箱子id和版本号等信息
            boxInfo = list.get(0);
            // 设置基础字段
            ParameterUtil.setUpdateEntity(boxInfo);
            // 设置当前用户id
            boxInfo.setUsedBy(SecurityUtils.getUserId());
            // 设置已使用
            boxInfo.setIsUsed(1);
            // 更新字段
            int count = boxInfoMapper.updateInfoIdVersion(boxInfo);
            if (count == 1) {
                return boxInfo;
            } else if (count == 0) {
                // 进入补偿机制
                return distributeBox(boxInfo);
            } else {
                // 手动抛异常
                throw new CustomException("自动分配箱子失败，请联系管理员", HttpStatus.ERROR);
            }
        } else {
            throw new CustomException("当前规格下无箱子");
        }
    }

    /**
     * 通过订单id查看订单详情
     *
     * @param orderVO 对象
     * @return 列表
     */
    @Override
    public OrderVO selectOrder(OrderVO orderVO) {
        // 返回结果
        return orderMapper.selectOrderId(orderVO);
    }

    /**
     * 订单操作
     *
     * @param orderVO 订单对象
     * @param status  订单状态
     * @param id      订单id
     * @param version 订单id的版本号
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateOperate(OrderOpreate orderOpreate, Long id, Integer status, Long version, OrderVO orderVO) {
        if (orderOpreate == null) {
            throw new CustomException("操作不规范");
        }
        // 插入订单历史表
        orderMapper.insertOrderHistory(id);
        // 查询当前订单信息
        Long userId = SecurityUtils.getUserId();
        orderVO.setId(id);
        OrderVO beforeVo = orderMapper.selectOrderId(orderVO);
        // 更新后的信息
        OrderVO afterVo = setBasic(id, status, version, orderVO);
        // 如果操作状态为存储成功操作，或是预约提取操作，订单完成操作
        if (beforeVo.getStatus().equals(1) && orderOpreate.equals(OrderOpreate.STORAGE_SUS) ||
                beforeVo.getStatus().equals(6) && orderOpreate.equals(OrderOpreate.ORDER_SUS_APP)) {
            // 开关锁
            openKey();
        }
        if (orderOpreate.equals(OrderOpreate.ORDER_EXTRACT)) {
            Long currentPoints = userMapper.selectCurrentPoints(userId);
            Long minPoints = 0L;
            if (currentPoints.compareTo(minPoints) <= 0) {
                throw new CustomException("积分不足无法取出请获取积分后等待再次尝试");
            }
            openKey();
        }
        // 如果操作状态为backend端的8 订单完成
        if (orderOpreate.equals(OrderOpreate.ORDER_SUS)) {
            // 定义我的更新参数count
            int count = orderMapper.updateStatus(afterVo);
            // 如果count==0说明没更新成功
            if (count == 0) {
                log.error("failed:乐观锁");
                // 如果更新成功返回更新历史表操作
                throw new CustomException("率先被他人修改刷新后重试");
            } else {
                // 实例化箱子对象
                BoxInfo boxInfo = new BoxInfo();
                // 取到当前订单信息的箱子id
                boxInfo.setId(beforeVo.getBoxId());
                // 设置箱子基础字段
                ParameterUtil.setUpdateEntity(boxInfo);
                // 清空用户id
                boxInfo.setUsedBy(null);
                // 设置未使用
                boxInfo.setIsUsed(0);
                // 更新箱子信息字段
                boxInfoMapper.updateBoxId(boxInfo);
                // 插入订单历史表
                return orderMapper.insertOrderHistory(id);
            }
        }
        // 如果操作状态为app端的8 删除订单
        if (orderOpreate.equals(OrderOpreate.DELETE_ORDER)) {
            // 定义我的更新参数count
            int count = orderMapper.updateStatus(afterVo);
            // 如果count==0说明没更新成功
            if (count == 0) {
                log.error("failed:乐观锁");
                // 抛出异常
                throw new CustomException("率先被他人修改刷新后重试");
            } else {
                // 删除订单
                orderMapper.deleteOrder(afterVo);
                // 插入订单历史表
                return orderMapper.insertOrderHistory(id);
            }
        }
        // 定义我的更新参数count
        int count = orderMapper.updateStatus(afterVo);
        // 如果count==0说明没更新成功
        if (count == 0) {
            log.error("failed:乐观锁");
            // 抛出异常
            throw new CustomException("率先被他人修改刷新后重试");
        } else {
            // 插入成功返回
            return count;
        }
    }

    /**
     * 后台端订单删除
     *
     * @param ids 订单id组数
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteOrderByIds(Long[] ids) {
        // 返回修改条数
        int result = orderMapper.deleteOrderByIds(ParameterUtil.getBatchUpdateMapByIds(ids));
        // 判断当前我传进去的id是否还有未完成的
        if (result != ids.length) {
            // 抛出异常
            throw new CustomException("当前订单中还有未完成订单，或是该用户下不存在此订单");
        } else {
            // 更新成功
            return orderMapper.insertOrderHistoryByIds(ParameterUtil.getBatchUpdateMapByIds(ids));
        }
    }

    /**
     * 批量更新超时不取的积分
     */
    @Override
    public void batchUpdateDelayOrder() {
        OrderVO orderVO = new OrderVO();
        orderVO.setStatus(2);
        List<OrderVO> orderVOS = orderMapper.selectOrderList(orderVO);
        orderVO.setStatus(5);
        orderVOS.addAll(orderMapper.selectOrderList(orderVO));
        LocalDateTime now = LocalDateTime.now();
        for (OrderVO vo : orderVOS) {
            // 将Date转为LocalDateTime
            LocalDateTime OrderTime = DateUtils.dateLocalDateTime(vo.getEmptyBoxOrderTime());
            LocalDateTime expireTime = OrderTime.plusHours(vo.getLeaseDuration());
            if (expireTime.isBefore(now)) {
                long unitPrice = Long.parseLong(vo.getBoxUnitPrice());
                // 实例化一个用户对象
                User user = new User();
                // 设置到用户当前积分中
                user.setCurrentPoints(-unitPrice);
                // 设置更新人
                user.setUpdateBy("Task");
                // 设置基础字段
                ParameterUtil.setUpdateEntity(user);
                // 设置userId
                user.setUserId(vo.getUserId());
                // 更新积分
                userMapper.operateUserPoints(user);
                // 插入积分记录
                pointService.insertPointRecord(RecordPointWay.TASK, vo.getUserId(), -unitPrice, null, vo.getId());
            }
        }
    }

    /**
     * 开关锁方法
     */
    public void openKey() {
        try {
            // 实例化socket对象
            Socket s = new Socket(HOST, PORT);
            // 创建字符输出流
            OutputStream os = s.getOutputStream();
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
            //向单片机服务器端发送开关指令
            bw.write(OPEN);
            // 立马发送
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置基础字段
     *
     * @param id      订单ID
     * @param status  状态
     * @param version 版本号
     * @param orderVO 订单对象
     */
    public OrderVO setBasic(Long id, Integer status, Long version, OrderVO orderVO) {
        // 设置基础字段
        ParameterUtil.setCreateEntityNoVersion(orderVO);
        // 设置状态
        orderVO.setStatus(status);
        // 设置订单id
        orderVO.setId(id);
        // 设置版本号
        orderVO.setVersion(version);

        return orderVO;
    }
}
